package com.training.admin.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.persistence.support.QueryFilter;
import com.demo2do.core.utils.CollectionUtils;
import com.training.admin.dao.ProjectDataDao;
import com.training.admin.dao.ProjectPhaseCourseDao;
import com.training.admin.dao.ProjectPhaseDao;
import com.training.admin.dto.ProjectDateRquest;
import com.training.admin.entity.category.TrainingCategory;
import com.training.admin.entity.department.Department;
import com.training.admin.entity.project.Project;
import com.training.admin.entity.project.ProjectPhase;
import com.training.admin.entity.project.ProjectPhaseCourse;
import com.training.admin.entity.project.ProjectTrainee;
import com.training.admin.entity.search.ProjectDataSearch;
import com.training.admin.service.DataService;
import com.training.admin.service.ProjectDataService;

/**
 * 
 * @author Rockett
 *
 */
@Service("projectService")
public class ProjectDataServiceImpl extends DataServiceImpl<Project> implements ProjectDataService {

	@Autowired
	private GenericDaoSupport genericDaoSupport;

	@Dao
	private ProjectDataDao projectDataDao;

	@Dao
	private ProjectPhaseDao projectPhaseDao;

	@Dao
	private ProjectPhaseCourseDao projectPhaseCourseDao;

	@Autowired
	@Qualifier("dataService")
	private DataService<Department> departmentService;

	/**
	 * 
	 * @param page
	 * @return
	 */
	private List<Project> list(Page page) {
		List<Project> projects = projectDataDao.list(page.getBeginIndex(), page.getEveryPage());
		page.calculate();
		return projects;
	}

	/**
	 * 
	 * @param departmentId
	 * @param page
	 * @return
	 */
	private List<Project> listByDepartmentId(Long departmentId, Page page) {
		List<Project> projects = projectDataDao.listByDepartmentId(departmentId, page.getBeginIndex(),
				page.getEveryPage());
		page.calculate();

		return projects;
	}

	/**
	 * 
	 * @return
	 */
	private int count() {
		return projectDataDao.countAll();
	}

	/**
	 * 
	 * @param departmentId
	 * @return
	 */
	private int countByDepartmentId(Long departmentId) {
		return projectDataDao.countByDepartmentId(departmentId);
	}

	/**
	 * 
	 * @param projectDataSearch
	 * @return
	 */
	private int count(ProjectDataSearch projectDataSearch) {

		String sentence = projectDataSearch.buildSentenceTemplate();

		Map<String, Object> parameters = projectDataSearch.buildParameters();

		return genericDaoSupport.count(sentence, parameters);

	}

	/**
	 * 
	 * @param departmentId
	 * @param projectDataSearch
	 * @return
	 */
	private int countByDepartmentId(Long departmentId, ProjectDataSearch projectDataSearch) {

		projectDataSearch = projectDataSearch.setDepartmentIds(departmentId);

		String sentence = projectDataSearch.buildSentenceTemplate();

		Map<String, Object> parameters = projectDataSearch.buildParameters();

		return genericDaoSupport.count(sentence, parameters);
	}

	/**
	 * 
	 * @param page
	 * @param projectDataSearch
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<Project> search(Page page, ProjectDataSearch projectDataSearch) {

		String sentence = projectDataSearch.buildSentenceTemplate();

		Map<String, Object> parameters = projectDataSearch.buildParameters();

		List<Project> projects = genericDaoSupport.searchForList(sentence, parameters, page.getBeginIndex(),
				page.getEveryPage());

		page.calculate();

		return projects;

	}

	/**
	 * 
	 * @param departmentId
	 * @param page
	 * @param projectDataSearch
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<Project> searchByDepartmentId(Long departmentId, Page page, ProjectDataSearch projectDataSearch) {

		projectDataSearch = projectDataSearch.setDepartmentIds(departmentId);

		String sentence = projectDataSearch.buildSentenceTemplate();

		Map<String, Object> parameters = projectDataSearch.buildParameters();

		List<Project> projects = genericDaoSupport.searchForList(sentence, parameters, page.getBeginIndex(),
				page.getEveryPage());

		page.calculate();

		return projects;

	}

	/**
	 * 
	 * @return
	 */
	private List<Department> listDepartmentAll() {

		return departmentService.listAll(Department.class);
	}

	/**
	 * 
	 * @param departmentId
	 * @return
	 */
	private List<Department> listDepartmentById(Long departmentId) {

		return projectDataDao.listDepartmentById(departmentId);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.demo2do.fms.admin.service.DataService#count(java.lang.Class,
	 * com.demo2do.core.persistence.support.QueryFilter)
	 */
	public int countAll(QueryFilter queryFilter) {

		return genericDaoSupport.searchForInt("SELECT COUNT(*) FROM Project WHERE " + queryFilter.clauseSentence(),
				queryFilter.parameters());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.training.admin.service.ProjectDataService#count(com.training.admin.entity
	 * .security.Login)
	 */
	public int count(Long departmentId) {

		if (departmentId == null) {

			return this.count();

		} else {

			return this.countByDepartmentId(departmentId);

		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.training.admin.service.ProjectDataService#list(com.training.admin.entity.
	 * security.Login, com.demo2do.core.entity.page.Page)
	 */
	public List<Project> list(Long departmentId, Page page) {

		if (departmentId == null) {

			return this.list(page);

		} else {

			return this.listByDepartmentId(departmentId, page);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.training.admin.service.ProjectDataService#search(java.lang.Long)
	 */
	public List<Project> onSearch(Long departmentId, ProjectDataSearch projectDataSearch, Page page) {

		if (departmentId == null) {

			return this.search(page, projectDataSearch);

		} else {

			return this.searchByDepartmentId(departmentId, page, projectDataSearch);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.training.admin.service.ProjectDataService#count(java.lang.Long,
	 * com.training.admin.entity.search.ProjectDataSearch)
	 */
	public int count(Long departmentId, ProjectDataSearch projectDataSearch) {

		if (departmentId == null) {

			return this.count(projectDataSearch);

		} else {

			return this.countByDepartmentId(departmentId, projectDataSearch);
		}

	}

	/*
	 * (non-Javadoc)
	 * @see com.training.admin.service.ProjectDataService#createProject(com.training.admin.entity.project.Project)
	 */
	public Project createProject(Project project) {

		genericDaoSupport.save(project.init(new Date()));
		for (int i = 0; i < project.getPhaseCount(); i++) {
			ProjectPhase projectPhase = new ProjectPhase();
			genericDaoSupport.save(projectPhase.init(project, (i + 1)));
		}
		
		return project;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.training.admin.service.ProjectDataService#editPhasesDate(java.util.Date,
	 * java.util.Date)
	 */
	public void editPhasesDate(Long id, ProjectDateRquest projectDateRquest) {
		
		Project project = genericDaoSupport.load(Project.class, id);

		List<ProjectPhase> projectPhases = projectDataDao.listByProjectId(id);
		Date minDate = projectDateRquest.getBeginDate().get(0);
		Date maxDate = projectDateRquest.getEndDate().get(0);

		for (int i = 0; i < projectPhases.size(); i++) {

			ProjectPhase projectPhase = projectPhases.get(i);

			Date date = projectDateRquest.getBeginDate().get(i);

			Date endDate = projectDateRquest.getEndDate().get(i);
			
			minDate = date.before(minDate) ? date : minDate;
			
			maxDate = endDate.after(maxDate) ? endDate : maxDate;
			
			projectPhase.editDate(date, endDate);

			genericDaoSupport.update(projectPhase);
		}
		genericDaoSupport.update(project.editDate(minDate, maxDate));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.training.admin.service.ProjectDataService#delete(java.lang.Long)
	 */
	@SuppressWarnings("unchecked")
    public void delete(Long id) {

		Project project = genericDaoSupport.load(Project.class, id);

		project.setDisabled(true);
		genericDaoSupport.update(project);

		// List<ProjectTrainee>
		List<ProjectTrainee> projectTeainees = projectDataDao.listProjectTraineeByProjectid(id);
		for (ProjectTrainee projectTrainee : projectTeainees) {
			genericDaoSupport.update(projectTrainee.delete());
		}
		
		List<ProjectPhase> projectPhases = projectDataDao.listByProjectId(id);
		for (ProjectPhase projectPhase : projectPhases) {
			genericDaoSupport.update(projectPhase.delete());
		}
		
		List<Long> phaseIds = CollectionUtils.extractPropertyList(projectPhases, "id");
		List<ProjectPhaseCourse> projectPhaseCourses = projectDataDao.listByprojectPhaseId(phaseIds);
		for (ProjectPhaseCourse projectPhaseCourse : projectPhaseCourses) {
            genericDaoSupport.update(projectPhaseCourse.delete());
        }

	}
	
	/*
	 * (non-Javadoc)
	 * @see com.training.admin.service.ProjectDataService#copy(java.lang.Long)
	 */
	public void copy(Long id) {
	    
	    Project oldProject = genericDaoSupport.load(Project.class, id);
	    if(oldProject == null) {
	        throw BusinessException.newInstance("500", "项目不存在");
	    }
	    
	    Project project = new Project(oldProject);
	    genericDaoSupport.save(project.init(new Date()));
	    
	    List<ProjectPhase> oldProjectPhases = projectDataDao.listByProjectId(id);
	    for(ProjectPhase oldProjectPhase : oldProjectPhases) {
	        ProjectPhase projectPhase = new ProjectPhase(oldProjectPhase);
	        genericDaoSupport.save(projectPhase.init(project, oldProjectPhase.getPhase()));
	        
	        List<Long> phaseIds = new ArrayList<>();
	        phaseIds.add(oldProjectPhase.getId());
	        List<ProjectPhaseCourse> oldProjectPhaseCourses = projectDataDao.listByprojectPhaseId(phaseIds);
	        
	        for(ProjectPhaseCourse  oldProjectPhaseCourse : oldProjectPhaseCourses) {
	            ProjectPhaseCourse projectPhaseCourse = new ProjectPhaseCourse(oldProjectPhaseCourse);
	            genericDaoSupport.save(projectPhaseCourse.init(projectPhase));
	        }
	    }
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.training.admin.service.ProjectDataService#listProjectPhaseById(java.lang.
	 * Long)
	 */
	public List<ProjectPhase> listProjectPhaseById(Long id) {
		return projectDataDao.listByProjectId(id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.training.admin.service.ProjectDataService#updateProject(com.training.
	 * admin.entity.project.Project)
	 */
	public void updateProject(Project project) {

		List<ProjectPhase> projectPhases = projectPhaseDao.listByProjectId(project.getId());

		for (ProjectPhase projectPhase : projectPhases) {
			genericDaoSupport.delete(projectPhase);
		}

		for (int i = 0; i < project.getPhaseCount(); i++) {
			ProjectPhase projectPhase = new ProjectPhase();
			genericDaoSupport.save(projectPhase.init(project, i + 1));
		}

		genericDaoSupport.update(project);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.training.admin.service.ProjectDataService#updateProject(com.training.
	 * admin.entity.project.Project,
	 * com.training.admin.entity.category.TrainingCategory,
	 * com.training.admin.entity.category.TrainingCategory,
	 * com.training.admin.entity.department.Department)
	 */
	public void updateProject(Project project, TrainingCategory firstCategory, TrainingCategory secondCategory, Department department) {

		List<ProjectPhase> projectPhases = projectPhaseDao.listByProject(project);
		int count = project.getPhaseCount() - projectPhases.size();
		
		if(count > 0) {
			for (int i = projectPhases.size(); i < project.getPhaseCount(); i++) {
				ProjectPhase projectPhase = new ProjectPhase();
				genericDaoSupport.save(projectPhase.init(project, i + 1));
			}
		} else {
			for(int i = 0;  i < projectPhases.size(); i++) {
				if(i+1 > project.getPhaseCount()) {
					genericDaoSupport.update(projectPhases.get(i).editDisabled());
					genericDaoSupport.executeHQL("UPDATE ProjectPhaseCourse SET disabled = true WHERE projectPhase.id = :id", "id", projectPhases.get(i).getId());
					genericDaoSupport.executeHQL("UPDATE SurveyNotifaction SET disabled = true WHERE projectPhase.id = :id", "id", projectPhases.get(i).getId());
					genericDaoSupport.executeHQL("DELETE TrainingResult  WHERE projectPhase.id = :id", "id", projectPhases.get(i).getId());
					genericDaoSupport.executeHQL("UPDATE TrainingSurvey SET disabled = true WHERE projectPhase.id = :id", "id", projectPhases.get(i).getId());
					genericDaoSupport.executeHQL("DELETE TrainingSurveyResult WHERE projectPhase.id = :id", "id", projectPhases.get(i).getId());
				}
			}
			List<ProjectPhase> newProjectPhases = projectPhaseDao.listByProject(project);
			if(org.apache.commons.collections.CollectionUtils.isNotEmpty(newProjectPhases)) {
				Date minDate = newProjectPhases.get(0).getBeginDate();
				minDate = minDate == null ? new Date() : minDate;
				Date maxDate = newProjectPhases.get(0).getEndDate();
				maxDate = maxDate == null ? new Date() : maxDate;
				for (int i = 0; i < newProjectPhases.size(); i++) {
					Date startDate = newProjectPhases.get(i).getBeginDate();
					Date endDate = newProjectPhases.get(i).getEndDate();
					minDate = startDate == null ? minDate: (startDate.before(minDate) ? startDate : minDate);
					maxDate = endDate == null ? maxDate : (endDate.after(maxDate) ? endDate : maxDate);
				}
				
				project.setBeginDate(minDate);
				project.setEndDate(maxDate);
				genericDaoSupport.update(project);
			}
		}

		genericDaoSupport.update(project.editInfo(firstCategory, secondCategory, department));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.training.admin.service.ProjectDataService#list()
	 */
	public List<Department> list(Long departmentId) {

		if (departmentId == null) {

			return this.listDepartmentAll();

		} else {

			return this.listDepartmentById(departmentId);

		}

	}

}
